package com.imooc.netty.samples.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 注:若是不想打印,则在idea中ctrl+R进行全局替换
 * 如"System.out"替换为"// System.out"
 */
public class ServerDemo {
    private static final int PORT = 10086;

    public static void main(String[] args) {
//        singleThreadProcess(); // 单线程处理
        multiThreadProcess(); // 多线程处理
    }

    /**
     * 单线程处理
     */
    private static void singleThreadProcess() {
        try {
            // 创建ServerSocket对象，指定监听的端口号
            ServerSocket serverSocket = new ServerSocket(PORT);
            // 启动、退出、新建链接使用err打印,因为err显示红色字体、仅为了方便观察
            System.err.println("server start successfully, server socket: " + serverSocket);
            // 监听客户端的连接请求(此处仅监听到第一个请求,因此只能处理一个,而下面的多线程处理将改行代码写在while中)
            Socket clientSocket = serverSocket.accept();
            System.err.println("client connected: " + clientSocket);
            // 获取输入流和输出流,输入流和输出流是通过socket对象来进行数据传输的。
            BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
            String message;
            while (true) {
                // 读取客户端发送的信息
                message = in.readLine();
                System.out.println("receive client msg: " + message);
                if (message.equalsIgnoreCase("exit")) {
                    // 如果接收到终止标志，退出循环
                    clientSocket.close();
                    System.err.println("exit successfully, client socket: " + clientSocket);
                    serverSocket.close();
                    System.err.println("exit successfully, server socket: " + serverSocket);
                    break;
                }

                // 发送响应给客户端(在收到的消息前拼接hello,随便简单处理的~)
                out.println("hello_" + message);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 多线程处理
     * 参考com.imooc.netty.samples.$03.BIOEchoServer
     */
    private static void multiThreadProcess() {
        try {
            ServerSocket serverSocket = new ServerSocket(PORT);
            System.err.println("server start successfully, server socket: " + serverSocket);
            int taskNum = 0;
            while (true) {
                // 监听客户端的连接请求(多线程处理时,serverSocket.accept这行代码写在while中)
                Socket clientSocket = serverSocket.accept();
                System.err.println("client connected: " + clientSocket);
                /*
                 * 监听到客户端的请求后,新启动线程去处理
                 * 也就是一个客户端对应一个服务端的线程,这样服务端开销较大性能不好,此处仅使用演示~
                 * (虽然该代码使用了线程池,但性能也一般)
                 * 更多理论模型,查阅select epoll等,可见netty讲解
                 */
                ServerTask serverTask = new ServerTask(clientSocket);
                String taskName = "serverTask-" + taskNum++;
                new Thread(serverTask, taskName).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static class ServerTask implements Runnable {
        private Socket clientSocket; // 该服务端任务,对应的客户端socket,与之绑定

        public ServerTask(Socket clientSocket) {
            this.clientSocket = clientSocket;
        }

        @Override
        public void run() {
            try {
                BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
                String message;
                while (true) {
                    message = in.readLine();
                    System.out.println("receive client msg: " + message);
                    if (message.equalsIgnoreCase("exit")) {
                        clientSocket.close();
                        System.err.println("exit successfully, client socket: " + clientSocket);
                        break;
                    }
                    out.println("hello_" + message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
